"""
    Implement some utility function in there.
"""

import numpy as np
import sys
import math

import torch


def gaussian_kernel_generation_1(kernel_size=5, sigma=1) -> np.ndarray:
    """
        Inspired by https://blog.csdn.net/wenhao_ir/article/details/124121440
    """
    if sigma == 0:
        print("ERROR: pass a zero variance to calculate gaussian kernel!")
        sys.exit()
    sigma_3 = 3 * sigma
    _x = np.linspace(-sigma_3, sigma_3, kernel_size)
    _y = np.linspace(-sigma_3, sigma_3, kernel_size)
    x, y = np.meshgrid(_x, _y)
    gauss_1 = 1 / (2 * np.pi * sigma ** 2) * np.exp(-(x ** 2 + y ** 2) / (2 * sigma ** 2))
    z = gauss_1.sum()
    gauss_2 = gauss_1 * (1 / z)
    return gauss_2


def gaussian_kernel_generation_2(radius=1, sigma=1) -> np.ndarray:
    def gaussian_calc(x, y):
        res1 = 1 / (2 * math.pi * sigma * sigma)
        res2 = math.exp(-(x * x + y * y) / (2 * sigma * sigma))
        return res1 * res2

    side_length = radius * 2 + 1
    result = np.zeros((side_length, side_length))
    for i in range(0, side_length):
        for j in range(0, side_length):
            result[i, j] = gaussian_calc(i - radius, j - radius)
    total = result.sum()
    return result / total


def gaussian_kernel_generation(kernel_size=5, sigma=1, channels=3) -> torch.Tensor:
    radium = kernel_size // 2
    constant = 1 / (2 * math.pi * sigma ** 2)
    gaussian_kernel = np.zeros((kernel_size, kernel_size))
    for i in range(0, kernel_size, 1):
        for j in range(0, kernel_size, 1):
            x = i - radium
            y = j - radium
            gaussian_kernel[i, j] = constant * math.exp(-0.5 / (sigma ** 2) * (x ** 2 + y ** 2))

    return torch.Tensor(gaussian_kernel / gaussian_kernel.sum()).expand(channels, 1, kernel_size, kernel_size)


if __name__ == "__main__":
    ...
